package com.ljk.study8httpfunction.httputil;

import okhttp3.*;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * desc:一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献，用于替代HttpUrlConnection和Apache HttpClient。
 *
 * @author ljk
 * @date 2021/3/31 20:51
 */
public class OkHttpUtil {
    public static void main(String[] args) throws IOException {
        String url = "http://127.0.0.1:8080/hello";
        Map<String, String> param = new HashMap<>(1) {
            {
                put("name", "ljk");
            }
        };
//        syncGet(url);
//        syncPost(url,param);
//        asyncGet(url);
//        asyncPostForm(url, param);
//        asyncPostString(url,"{\"name\":\"ljk\"}");
        System.err.println("方法结束");
    }

    /**
     * 同步的get请求
     *
     * @param url 请求链接
     * @throws Exception
     */
    public static void syncGet(String url) throws IOException {
        // 创建OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        // 创建一个请求
        Request request = new Request.Builder().url(url).get().build();
        // 返回实体
        Response response = okHttpClient.newCall(request).execute();
        // 判断是否成功
        if (response.isSuccessful()) {
            /**获取返回的数据，可通过response.body().string()获取，默认返回的是utf-8格式；
             * string()适用于获取小数据信息，如果返回的数据超过1M，建议使用stream()获取返回的数据，
             * 因为string() 方法会将整个文档加载到内存中。*/
            // 打印数据
            System.out.println(response.body().string());
        } else {
            // 链接失败
            System.out.println("失败");
        }
    }

    /**
     * 同步的post请求
     *
     * @param url    请求链接
     * @param params 请求参数
     */
    public static void syncPost(String url, Map<String, String> params) {
        OkHttpClient client = new OkHttpClient();
        //组装键值，params为键值，name为属性名
        FormBody.Builder builder = new FormBody.Builder();
        params.entrySet().forEach(param -> {
            builder.add(param.getKey(), param.getValue());
        });
        FormBody formBody = builder.build();
        //组装请求头
        Request request = new Request.Builder().url(url).post(formBody).build();
        //该方法容易触发IOException异常
        try {
            //获取返回值
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println(response.body().string());
            } else {
                System.out.println("error!");
                System.err.println(response);
            }
        } catch (IOException ie) {
            ie.printStackTrace();
        }
    }

    /**
     * 异步的get请求
     *
     * @param url 请求链接
     * @throws IOException
     */
    public static void asyncGet(String url) {
        // 创建OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        // 创建一个请求
        Request request = new Request.Builder().url(url).get().build();
        // 返回实体
        okHttpClient.newCall(request).enqueue(new MyCallback());
    }


    /**
     * 异步的Post提交表单
     *
     * @param url    请求链接
     * @param params 请求参数
     */
    public static void asyncPostForm(String url, Map<String, String> params) {
        // OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        // 表单键值对
        FormBody.Builder builder = new FormBody.Builder();
        params.entrySet().forEach(param -> {
            builder.add(param.getKey(), param.getValue());
        });
        FormBody formBody = builder.build();
        // 请求
        Request request = new Request.Builder().url(url).post(formBody).build();
        // 回调
        okHttpClient.newCall(request).enqueue(new MyCallback());
    }

    /**
     * <p>不推荐</p>
     * 异步的Post提交字符串
     * 使用Post方法发送一串字符串，但不建议发送超过1M的文本信息
     *
     * @param url   请求链接
     * @param param 要发送的字符串
     */
    public static void asyncPostString(String url, String param) {
        MediaType MEDIA_TYPE = MediaType.parse("text/text; charset=utf-8");
        // OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        /**
         * RequestBody.create(MEDIA_TYPE, string)
         * 第二个参数可以分别为：byte[]，byteString,File,String。
         */
        Request request = new Request.Builder().url(url)
                .post(RequestBody.create(MEDIA_TYPE, param)).build();
        okHttpClient.newCall(request).enqueue(new MyCallback());
    }

    /**
     *使用okhttp调用http的通用方法
     * @param url 地址
     * @param params 入参
     * @param method 请求的方法
     * @param sync 是否为同步请求
     * @throws IOException
     */
    public static void okHttpDemo(@NotNull String url,Map<String,String> params,@NotNull String method,boolean sync) throws IOException {
        // 创建OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //form表单赋值
        FormBody formBody = null;
        if (params!=null&&params.size()!=0){
            FormBody.Builder builder = new FormBody.Builder();
            params.entrySet().forEach(param -> {
                builder.add(param.getKey(), param.getValue());
            });
            formBody = builder.build();
        }
        // 创建一个请求
        Request request = new Request.Builder()
                //设置url
                .url(url)
                //定义请求方法 常见的.get  .post 还有
                .method(method.toUpperCase(),formBody)
                //确定构建
                .build();
        Call call = okHttpClient.newCall(request);
        if(sync) {
            Response response = call.execute();
            // 判断是否成功
            if (response.isSuccessful()) {
                /**获取返回的数据，可通过response.body().string()获取，默认返回的是utf-8格式；
                 * string()适用于获取小数据信息，如果返回的数据超过1M，建议使用stream()获取返回的数据，
                 * 因为string() 方法会将整个文档加载到内存中。*/
                // 打印数据
                System.out.println(response.body().string());
            } else {
                // 链接失败
                System.out.println("失败");
            }
        }else{
            call.enqueue(new MyCallback());
        }
    }












}

/**
 * 回调方法,当请求时放上此类代表异步请求
 */
class MyCallback implements Callback {
    /**
     * 错误时的做法
     *
     * @param call
     * @param e
     */
    @Override
    public void onFailure(@NotNull Call call, @NotNull IOException e) {
        System.out.println(e.getMessage());
    }

    /**
     * 成功后的做法
     *
     * @param call
     * @param response
     * @throws IOException
     */
    @Override
    public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
        System.out.println(response.body().string());
    }
}